#include "peerlist.h"

guint peerlist_hash(gconstpointer ptr) {
	guint32 id = ptr;
	return id;
}

void peerlist_free_packet(gpointer data) {
	pkt_pong *p = data;
	free(p);
}

void printf_peer(gpointer key, gpointer value, gpointer user_data) {
	pkt_pong *p = value;
	printf("PEER ELEMENT: port %d\n", p->listening_port);	
}

gboolean peerlist_keyequal(gconstpointer ptr1, gconstpointer ptr2) {
	guint32 id1=ptr1, id2=ptr2;
	if(id1 == id2)
		return TRUE;
	else
		return FALSE;
}

void peerlist_init() {
	pthread_mutex_init(&peerlist_mtx, NULL);
	peerlist = g_hash_table_new_full((GHashFunc)peerlist_hash, (GEqualFunc)peerlist_keyequal, NULL, (GDestroyNotify)peerlist_free_packet);
}

pkt_pong* peerlist_get(guint32 key) {
	lock_peerlist();
	pkt_pong *p = g_hash_table_lookup(peerlist, key);
	unlock_peerlist();
	return p;
}

void peerlist_add(pkt_pong *p) {
	lock_peerlist();
	gpointer old = g_hash_table_lookup(peerlist, p->id);
	if(old) {
		unlock_peerlist();
		return;
	}
	n_malloc_zs(np, pkt_pong);
	memcpy(np, p, sizeof(pkt_pong));
	
	printf("ADDING PEER (port: %d, id:%d)\n", np->listening_port, np->id);
	g_hash_table_insert(peerlist, np->id, np);
	unlock_peerlist();
}

void peerlist_to_FILE(gpointer key, gpointer value, gpointer user_data) {
	FILE *f = (FILE*)user_data;
	pkt_pong *p = value;
	struct in_addr a;
	a.s_addr = p->address;
	
	char *address = inet_ntoa(a);
	char port[256];
	fwrite(address, sizeof(char), strlen(address), f);
	fwrite(":", sizeof(char), 1, f);
	itoa(p->listening_port, port);
	fwrite(port, sizeof(char), strlen(port), f);
	fwrite("\n", sizeof(char), 1, f);
}

gboolean peertonode_condition(gpointer key, gpointer value, gpointer user_data) {
	node *n;
	pkt_pong *p = value;
	struct in_addr a;
	a.s_addr = p->address;
	int found = 0;
	for_each_node(n)
		if(n->id == p->id || (strcmp(inet_ntoa(a),n->c->address)==0 && p->listening_port==n->c->listening_port)){
			printf("[peernode_condition] trovato nodo %d\n", n->id);
			return FALSE;
		}
	
		printf("[peernode_condition] non trovato nodo %d, ip %s, port %d\n", p->id, inet_ntoa(a), p->listening_port);
	return TRUE;
}

int peerlist_to_nodecache() {
	lock_peerlist();
	pkt_pong *p;
	guint32 id;
	
	p=(pkt_pong*)g_hash_table_find(peerlist,peertonode_condition,NULL);
	
	if(p==NULL) {
		unlock_peerlist();
		return 0;
	}
	
	struct in_addr a;
	a.s_addr = p->address;
	
	add_node(inet_ntoa(a), p->listening_port, p->id, CONNECTION_TYPE_CONNECT);
	
	g_hash_table_remove(peerlist, p->id);
	
	unlock_peerlist();
	
	return 1;
}

void __peerlist_to_nodecache() {
	return;
	lock_peerlist();
	//GHashTableIter iter;
	int iter;
	pkt_pong p;
	guint32 id;
	
	//g_hash_table_iter_init(&iter, peerlist);
	//g_hash_table_iter_next(&iter, &id, &p);
	
	struct in_addr a;
	a.s_addr = p.address;
	
	add_node(inet_ntoa(a), p.listening_port, id, CONNECTION_TYPE_CONNECT);
	
	g_hash_table_remove(peerlist, id);
	
	unlock_peerlist();
}

void _peerlist_to_nodecache() {
	printf("glib version %d.%d.%d\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
	
	lock_peerlist();
	if(g_hash_table_size(peerlist)==0)
		return;
	
	GList* peers = g_hash_table_get_values(peerlist);
	GList* ids = g_hash_table_get_keys(peerlist);
	
	pkt_pong *p = g_list_first(peerlist)->data;
	guint32 id = g_list_first(ids)->data;
	
	struct in_addr a;
	a.s_addr = p->address;
	printf("[peerlist_to_nodecache] pong ip'%s' port'%d'", inet_ntoa(a), p->listening_port);
	add_node(inet_ntoa(a), p->listening_port, id, CONNECTION_TYPE_CONNECT);
	g_hash_table_remove(peerlist, id);
	
	g_list_free(ids);
	g_list_free(peers);
	unlock_peerlist();
}